#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>       // 线程相关库
#include <sys/socket.h>    // 套接字库
#include <netinet/in.h>    // 网络协议相关头文件
#include <sys/types.h>     // 基本系统数据类型
#include <unistd.h>        // 提供 `sleep`、`fork` 等函数
#include <netdb.h>         // 网络数据库操作（如域名解析）
#include <math.h>          // 数学函数库
#include <sys/time.h>      // 时间相关函数库
#include "common.h"        // 自定义公共头文件
#include "util.h"          // 链表、时间计算等工具函数
#include "input.h"         // 输入处理相关函数
#include "communicate.h"   // 模拟通信相关函数
#include "receiver.h"      // 接收方相关结构与函数
#include "sender.h"        // 发送方相关结构与函数

Sender * glb_senders_array;
Receiver * glb_receivers_array;
int glb_senders_array_length;
int glb_receivers_array_length;
SysConfig glb_sysconfig;
int CORRUPTION_BITS;


SlidingWindow *sliding_windows[10];//定义十个窗口

int main(int argc, char *argv[])
{
    pthread_t stdin_thread;                // 标准输入线程
    pthread_t * sender_threads;           // 发送方线程数组
    pthread_t * receiver_threads;         // 接收方线程数组
    int i;                                // 循环变量
    unsigned char print_usage = 0;        // 用于控制是否打印使用说明

    // DO NOT CHANGE THIS
    // 设置数据包损坏时更改的位数
    CORRUPTION_BITS = (int) MAX_FRAME_SIZE / 2;

    // DO NOT CHANGE THIS
    // 初始化系统配置对象 glb_sysconfig
    glb_sysconfig.drop_prob = 0;          // 数据包丢失概率
    glb_sysconfig.corrupt_prob = 0;       // 数据包损坏概率
    glb_sysconfig.automated = 0;          // 自动化输入标志
    memset(glb_sysconfig.automated_file, 0, AUTOMATED_FILENAME);

    // DO NOT CHANGE THIS
    // 初始化其他变量并设置随机数种子
    glb_receivers_array_length = -1;
    glb_senders_array_length = -1;
    srand(time(NULL));                    // 随机种子，确保每次执行结果不同

    // 解析命令行参数
    for (i = 1; i < argc;) 
    {
        if (strcmp(argv[i], "-s") == 0) // 解析发送方数量
        {
            sscanf(argv[i+1], "%d", &glb_senders_array_length);
            i += 2;
        }
        else if (strcmp(argv[i], "-r") == 0) // 解析接收方数量
        {
            sscanf(argv[i+1], "%d", &glb_receivers_array_length);
            i += 2;
        }      
        else if (strcmp(argv[i], "-d") == 0) // 解析丢包概率
        {
            sscanf(argv[i+1], "%f", &glb_sysconfig.drop_prob);
            i += 2;
        }      
        else if (strcmp(argv[i], "-c") == 0) // 解析损坏概率
        {
            sscanf(argv[i+1], "%f", &glb_sysconfig.corrupt_prob);
            i += 2;
        }
        else if (strcmp(argv[i], "-a") == 0) // 解析自动化输入文件
        {
            int filename_len = strlen(argv[i+1]);
            if (filename_len < AUTOMATED_FILENAME)
            {
                glb_sysconfig.automated = 1;
                strcpy(glb_sysconfig.automated_file, argv[i+1]);
            }
            i += 2;
        }     
        else if (strcmp(argv[i], "-h") == 0) // 打印帮助信息
        {
            print_usage = 1;
            i++;
        }     
        else
        {
            i++;
        }
    }

    // 检查输入的参数是否有效
    if (glb_senders_array_length <= 0 ||
        glb_receivers_array_length <= 0 ||
        (glb_sysconfig.drop_prob < 0 || glb_sysconfig.drop_prob > 1) ||
        (glb_sysconfig.corrupt_prob < 0 || glb_sysconfig.corrupt_prob > 1) ||
        print_usage)
    {
        fprintf(stderr, "USAGE: etherchat \n   -r int [# of receivers] \n   -s int [# of senders] \n   -c float [0 <= corruption prob <= 1] \n   -d float [0 <= drop prob <= 1]\n");
        exit(1);
    }
    
        
    // 创建标准输入处理线程
    int rc = pthread_create(&stdin_thread, NULL, run_stdinthread, (void *) 0);
    if (rc)
    {
        fprintf(stderr, "ERROR; return code from pthread_create() is %d\n", rc);
        exit(-1);
    }

    // 分配内存空间，用于存储发送方和接收方线程
    sender_threads = (pthread_t *) malloc(sizeof(pthread_t) * glb_senders_array_length);
    receiver_threads = (pthread_t *) malloc(sizeof(pthread_t) * glb_receivers_array_length);

    // 初始化发送方和接收方数组
    glb_senders_array = (Sender *) malloc(glb_senders_array_length * sizeof(Sender));
    glb_receivers_array = (Receiver *) malloc(glb_receivers_array_length * sizeof(Receiver));
    
    fprintf(stderr, "Messages will be dropped with probability=%f\n", glb_sysconfig.drop_prob);
    fprintf(stderr, "Messages will be corrupted with probability=%f\n", glb_sysconfig.corrupt_prob);
    fprintf(stderr, "Available sender id(s):\n");

    // 初始化发送方对象并分配 id
    for (i = 0; i < glb_senders_array_length; i++)
    {
        init_sender(&glb_senders_array[i], i);
        fprintf(stderr, "   send_id=%d\n", i);
    }

    // 初始化接收方对象并分配 id
    fprintf(stderr, "Available receiver id(s):\n");
    for (i = 0; i < glb_receivers_array_length; i++)
    {
        init_receiver(&glb_receivers_array[i], i);
        fprintf(stderr, "   recv_id=%d\n", i);
    }
    
    // 创建发送方线程
    for (i = 0; i < glb_senders_array_length; i++)
    {
        rc = pthread_create(sender_threads + i, NULL, run_sender, (void *) &glb_senders_array[i]);
        if (rc){
            fprintf(stderr, "ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }

    // 创建接收方线程
    for (i = 0; i < glb_receivers_array_length; i++)
    {
        rc = pthread_create(receiver_threads + i, NULL, run_receiver, (void *) &glb_receivers_array[i]);
        if (rc){
            fprintf(stderr, "ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
    }

    // 等待标准输入线程结束
    pthread_join(stdin_thread, NULL);

    // 终止并回收所有发送方线程
    for (i = 0; i < glb_senders_array_length; i++)
    {
        pthread_cancel(sender_threads[i]);
        pthread_join(sender_threads[i], NULL);
    }

    // 终止并回收所有接收方线程
    for (i = 0; i < glb_receivers_array_length; i++)
    {
        pthread_cancel(receiver_threads[i]);
        pthread_join(receiver_threads[i], NULL);
    }

    // 释放动态分配的内存
    free(sender_threads);
    free(receiver_threads);
    free(glb_senders_array);
    free(glb_receivers_array);

    return 0;
}
